/**
 * 
 */
package de.uni_leipzig.informatik.asv.unsupervised_pos_tagger.data;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntIterator;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import de.uni_leipzig.informatik.asv.util.Encoder;
import de.uni_leipzig.informatik.asv.util.IntegerCombine;
import de.uni_leipzig.informatik.asv.util.MixingIterator;
/**
 * 
 * @author Christoph Teichmann
 * created May 29, 2014 9:00:00 PM
 * @version 0.1
 */
public class MultinomialOnlyCorpus implements WordCorpus
{
	/**
	 * 
	 */
	private static final String WORDLANGUAGEMARKER = "\\|";
	/**
	 * 
	 */
	private static final String MULTINOMIAL = "multinomial";
	/**
	 * 
	 */
	private static final String COMMENT = "%%";
	/**
	 * 
	 */
	private final ArrayList<Word> data = new ArrayList<>();
	/**
	 * 
	 */
	private final Encoder enc = new Encoder();
	/**
	 * 
	 */
	private final Int2IntOpenHashMap featureToGroup = new Int2IntOpenHashMap();
	/* (non-Javadoc)
	 * @see java.lang.Iterable#iterator()
	 */
	@Override
	public Iterator<Word> iterator()
	{return data.iterator();}
	/* (non-Javadoc)
	 * @see de.uni_leipzig.informatik.asv.unsupervised_pos_tagger.data.WordCorpus#mIterator()
	 */
	@Override
	public MixingIterator<Word> mIterator()
	{return new MixingIterator<Word>(this.data);}
	/**
	 * 
	 * @param br
	 * @throws IOException
	 */
	private void addWords(BufferedReader br) throws IOException
	{
		String line;
		while((line = br.readLine()) != null)
		{
			line = line.trim();
			if(!line.matches(COMMENT))
			{
				String[] parts = line.split("\\s+");
				String[] bar = parts[0].split(WORDLANGUAGEMARKER);
				Word w = new Word(this.enc.ensure(bar[0]), this.enc.ensure(bar[1]),
															Double.parseDouble(parts[1]));
				this.words.put(encodeWord(w), w);
				this.data.add(w);
				for(int i=2;i<parts.length;i += 2)
				{
					int feat = this.enc.ensure(parts[i]);
					double val = Double.parseDouble(parts[i+1]);
					if(!this.featureToGroup.containsKey(feat))
					{throw new IllegalArgumentException("Feature unknown or not multinomial: "+parts[i]+
							" occured in word: "+parts[0]);}
					w.addFeature(feat, val);
				}
			}
		}
	}
	/**
	 *
	 * @param w
	 * @return
	 */
	private long encodeWord(Word w)
	{return IntegerCombine.combine(w.getIdentity(), w.getLanguage());}
	/* (non-Javadoc)
	 * @see de.uni_leipzig.informatik.asv.unsupervised_pos_tagger.data.WordCorpus#addFeatures(java.io.BufferedReader)
	 */
	@Override
	public void addFeatures(BufferedReader br) throws IOException
	{
		String line;
		while((line = br.readLine()) != null)
		{
			line = line.trim();
			if(!line.matches(COMMENT))
			{
				String[] parts = line.split("\\s+");
				if(parts[2].equals(MULTINOMIAL))
				{this.featureToGroup.put(this.enc.ensure(parts[0]), this.enc.ensure(parts[1]));}
			}
		}
	}
	/**
	 * 
	 */
	private final Long2ObjectOpenHashMap<Word> words = new Long2ObjectOpenHashMap<>();
	/* (non-Javadoc)
	 * @see de.uni_leipzig.informatik.asv.unsupervised_pos_tagger.data.WordCorpus#getFeatureGroup(int)
	 */
	@Override
	public int getFeatureGroup(int label)
	{return this.featureToGroup.get(label);}
	/* (non-Javadoc)
	 * @see de.uni_leipzig.informatik.asv.unsupervised_pos_tagger.data.WordCorpus#getLanguageIterator()
	 */
	@Override
	public IntIterator getLanguageIterator()
	{return languages.iterator();}
	/**
	 * 
	 */
	private final IntSet languages = new IntOpenHashSet();
	/* (non-Javadoc)
	 * @see de.uni_leipzig.informatik.asv.unsupervised_pos_tagger.data.WordCorpus#getLanguageName(int)
	 */
	@Override
	public String getLanguageName(int lang)
	{return this.enc.revert(lang);}
	/* (non-Javadoc)
	 * @see de.uni_leipzig.informatik.asv.unsupervised_pos_tagger.data.WordCorpus#getName(int)
	 */
	@Override
	public String getName(int identity)
	{return this.enc.revert(identity);}
	/**
	 * 
	 * @param br
	 * @throws IOException
	 */
	private void addConnections(BufferedReader br) throws IOException
	{
		String line;
		while((line = br.readLine()) != null)
		{
			line = line.trim();
			if(!line.matches(COMMENT))
			{
				String[] parts = line.split("\\s+");
				String[] bar = parts[0].split(WORDLANGUAGEMARKER);
				int word = this.enc.ensure(bar[0]);
				int language = this.enc.ensure(bar[1]);
				Word w = this.words.get(IntegerCombine.combine(word, language));
				double val = Double.parseDouble(parts[3]);
				bar = parts[1].split(WORDLANGUAGEMARKER);
				word = this.enc.ensure(bar[0]);
				language = this.enc.ensure(bar[1]);
				Word other = this.words.get(IntegerCombine.combine(word, language));
				int label = this.enc.ensure(parts[2]);
				w.addConnection(other, label, val);
			}
		}
	}
	@Override
	public void addWordsAndConnections(BufferedReader words,
			BufferedReader connections) throws IOException
	{
		this.addWords(words);
		this.addConnections(connections);
		this.words.clear();
	}
}